package com.xiguaji.tiktok.v1.tiktok.aweme.service;

import cn.hutool.core.date.DateUtil;
import com.xiguaji.boot.filecenter.FileTemplate;
import com.xiguaji.boot.toolkit.DateTimeUtils;
import com.xiguaji.boot.toolkit.JsonUtil;
import com.xiguaji.tiktok.utils.ESUtil;
import com.xiguaji.tiktok.utils.Ret;
import com.xiguaji.tiktok.v1.tiktok.aweme.dto.AwemeCountDto;
import com.xiguaji.tiktok.v1.tiktok.aweme.dto.AwemeHashtagResponse;
import com.xiguaji.tiktok.v1.tiktok.aweme.dto.AwemeMentionResponse;
import com.xiguaji.tiktok.v1.tiktok.aweme.dto.SearchData;
import com.xiguaji.tiktok.v1.tiktok.aweme.model.Aweme;
import com.xiguaji.tiktok.v1.tiktok.aweme.repository.AwemeHashtagRepository;
import com.xiguaji.tiktok.v1.tiktok.aweme.repository.AwemeMentionRepository;
import com.xiguaji.tiktok.v1.tiktok.aweme.repository.AwemeRepository;
import com.xiguaji.tiktok.v1.tiktok.blogger.repository.BloggerRepository;
import com.xiguaji.tiktok.v1.tiktok.collect.repository.AwemeCollectionRepository;
import lombok.val;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

@Service
public class AwemeService {

    @Autowired
    AwemeRepository awemeRepository;

    @Autowired
    BloggerRepository bloggerRepository;

    @Autowired
    RestHighLevelClient client;

    @Autowired
    ESUtil esUtil;

    @Autowired
    FileTemplate fileTemplate;

    @Autowired
    AwemeCollectionRepository awemeCollectionRepository;

    /*@Autowired(required = false)
    S3Template s3Template;*/

    @Autowired
    AwemeHashtagRepository awemeHashtagRepository;

    @Autowired
    AwemeMentionRepository awemeMentionRepository;

    @Value("${xiguaji.oss.bucket.tiktok.videoComment}")
    private String BUCKET_NAME = "xigua-tiktok-comment";

    double [] views = new double[]{10,100,500,1000,2000,5000};
    double [] likes = new double[]{10,50,100,500,1000,2000};
    double [] reviews = new double[]{0.5,1,5,10,50,100};
    double [] shares = new double[]{0.5,1,5,10,50,100};
    double [] duration = new double[]{15,30,60};
    int [] createDate = new int[]{6,12,24,3*24,7*24,15*24,30*24,60*24,90*24};

    public String getPageEs(SearchData searchData,long userId) throws IOException {
        SearchRequest searchRequest = new SearchRequest(esUtil.getAwemeIndex());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if(!StringUtils.isEmpty(searchData.getKeyWord())){
            boolQueryBuilder.should(QueryBuilders.nestedQuery("awemeTags",QueryBuilders.matchQuery("awemeTags.keyword",searchData.getKeyWord()), ScoreMode.Total));
            // boolQueryBuilder.should(QueryBuilders.wildcardQuery("title",searchData.getKeyWord());
            boolQueryBuilder.should(QueryBuilders.multiMatchQuery(searchData.getKeyWord(),"title"));
            boolQueryBuilder.should(QueryBuilders.matchQuery("shareUrl",searchData.getKeyWord()));
            boolQueryBuilder.minimumShouldMatch(1);
        }

        if(!StringUtils.isEmpty(searchData.getCategory())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("awemeType",searchData.getCategory()));
        }

        if(null != searchData.getCreateDate() && searchData.getCreateDate() <= createDate.length){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime")
                    .gte(DateTimeUtils.currentTimeSecond()-createDate[searchData.getCreateDate()]*60*60));
        }


        if(null != searchData.getViews() && searchData.getViews() > 0){
            int index = searchData.getViews() -1;
            if(index == 0){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("playCount").lt(views[index]*1000));
            }else if(index >= views.length){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("playCount").gte(views[views.length-1]*1000));
            }else{
                boolQueryBuilder.must(QueryBuilders.rangeQuery("playCount").gte(views[index-1]*1000).lte(views[index]*1000));
            }
        }
        if(null != searchData.getReviews() && searchData.getReviews() > 0){
            int index = searchData.getReviews() -1;
            if(index == 0){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("commentCount").lt(reviews[index]*1000));
            }else if(index >= reviews.length){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("commentCount").gte(reviews[reviews.length-1]*1000));
            }else{
                boolQueryBuilder.must(QueryBuilders.rangeQuery("commentCount").gte(reviews[index-1]*1000).lte(reviews[index]*1000));
            }
        }
        if(null != searchData.getLikes() && searchData.getLikes() > 0){
            int index = searchData.getLikes() -1;
            if(index == 0){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("diggCount").lt(likes[index]*1000));
            }else if(index >= likes.length){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("diggCount").gte(likes[likes.length-1]*1000));
            }else{
                boolQueryBuilder.must(QueryBuilders.rangeQuery("diggCount").gte(likes[index-1]*1000).lte(likes[index]*1000));
            }
        }
        if(null != searchData.getShare() && searchData.getShare() > 0){
            int index = searchData.getShare() -1;
            if(index == 0){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("shareCount").lt(shares[index]*1000));
            }else if(index >= shares.length){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("shareCount").gte(shares[shares.length-1]*1000));
            }else{
                boolQueryBuilder.must(QueryBuilders.rangeQuery("shareCount").gte(shares[index-1]*1000).lte(shares[index]*1000));
            }
        }
        if(null != searchData.getDuration()&& searchData.getDuration() > 0){
            int index = searchData.getDuration() -1;
            if(index == 0){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("duration").gt(0).lte(duration[index]*1000));
            }else if(index >= duration.length){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("duration").gte(duration[duration.length-2]*1000).lte(duration[duration.length-1]*1000));
            }else{
                boolQueryBuilder.must(QueryBuilders.rangeQuery("duration").gte(duration[index-1]*1000).lte(duration[index]*1000));
            }
        }

        String sort = "score";

        switch (searchData.getSort()){
            case 1:
                sort = "score";
                break;
            case 2:
                sort = "playCount";
                break;
            case 3:
                sort = "diggCount";
                break;
            case 4:
                sort = "commentCount";
                break;
            case 5:
                sort = "shareCount";
                break;
            default:
                break;
        }

        /*if(null != searchData.getCreateDate() && searchData.getCreateDate() >2){
            //boolQueryBuilder.minimumShouldMatch(3);
            boolQueryBuilder.must(QueryBuilders.rangeQuery("commentCount").gt(50));
            BoolQueryBuilder boolQueryBuilder2 = new BoolQueryBuilder();
            boolQueryBuilder2.must(QueryBuilders.existsQuery("awemeTags"));
            boolQueryBuilder.must(QueryBuilders.nestedQuery("awemeTags",boolQueryBuilder2, ScoreMode.Total));
        }*/

        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.sort(sort, SortOrder.DESC);
        searchSourceBuilder.from((searchData.getPage()-1)*searchData.getPageSize());
        searchSourceBuilder.size(searchData.getPageSize());
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        val value = searchResponse.getHits().getTotalHits().value;
        val hits = searchResponse.getHits().getHits();
        List<Map<String,Object>> data = new ArrayList<>();

        for (SearchHit hit : hits) {
            val map = JsonUtil.jsonParse(Map.class, hit.getSourceAsString());
            // val blogger = bloggerRepository.findByOUid(Long.parseLong(map.get("uid").toString())).get();
            val awemeOptional = awemeCollectionRepository.findByAwemeIdAndUserId(Long.parseLong(map.get("awemeId").toString()), userId);

            if(awemeOptional.isPresent()){
                map.put("favorite",true);
                map.put("collectId",awemeOptional.get().getId());
            }else{
                map.put("favorite",false);
                map.put("collectId",null);
            }

            /*if(null != blogger){
                map.put("bloggerId",blogger.getId());
                map.put("uniqueId",blogger.getOUniqueId());
            }*/
            data.add(map);
        }

        return Ret.pageData(value,data);
    }

    public Map<String,Object> getAwemeDetailEs(long awemeId,long userId) throws IOException {
        SearchRequest searchRequest = new SearchRequest(esUtil.getAwemeIndex());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchQuery("awemeId",awemeId));
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest,RequestOptions.DEFAULT);

        if(searchResponse.getHits().getHits().length == 0){
            return null;
        }

        val source = JsonUtil.jsonParse(Map.class,searchResponse.getHits().getHits()[0].getSourceAsString());
        val blogger = bloggerRepository.findByOUid(Long.parseLong(source.get("uid").toString())).get();
        val awemeOptional = awemeCollectionRepository.findByAwemeIdAndUserId(Long.parseLong(source.get("awemeId").toString()), userId);

        if(awemeOptional.isPresent()){
            source.put("favorite",true);
            source.put("collectId",awemeOptional.get().getId());
        }else{
            source.put("favorite",false);
            source.put("collectId",null);
        }

        if(null != blogger){
            Map<String,Object> bloggerMap = new HashMap<>();
            bloggerMap.put("uid",blogger.getOUid());
            bloggerMap.put("score",blogger.getScore());
            bloggerMap.put("followers",blogger.getOFollowerCount());
            bloggerMap.put("avgViews",blogger.getOAvgViews());
            bloggerMap.put("avgLikes",blogger.getOAvgLikes());
            bloggerMap.put("avgReviews",blogger.getOAvgReviews());
            bloggerMap.put("avgShare",blogger.getOAvgShare());
            bloggerMap.put("nickname",blogger.getONickname());
            bloggerMap.put("uniqueId",blogger.getOUniqueId());
            bloggerMap.put("avatar",blogger.getOAvatar168());
            source.put("bloggerInfo",bloggerMap);
        }
        return source;
    }


    public String getAwemeComments(long awemeId,int page,int pageSize){
        int totalCount = 0;
        List<Map<String,Object>> curList = new ArrayList<>();

        val comments = getComments(awemeId);
        if (null != comments){

            comments.sort((Object o1,Object o2)->{
                Map<String,Object> c1 = (Map<String,Object>)o1;
                Map<String,Object> c2 = (Map<String,Object>)o2;

                if((int)c1.get("diggCount") > (int)c2.get("diggCount")){
                    return -1;
                }else if((int)c1.get("diggCount") < (int)c2.get("diggCount")){
                    return 1;
                }
                return 0;
            });

            totalCount = comments.size();
            int fromIndex = (page - 1) * pageSize;
            int toIndex = fromIndex + pageSize;
            toIndex = toIndex > comments.size()?comments.size():toIndex;
            try{
                curList = comments.subList(fromIndex,toIndex);
            }catch (Exception e){
                curList = null;
            }

            curList.forEach( c->{
                c.put("defaultAvatar","https://webapi.gugeedata.com/static/img/avatar.png");
            });
        }
        return Ret.pageData(totalCount,curList);
    }

    // @Cacheable(value = "BLOGGER:AWEME:ALL:HASHTAG",key = "#uid")
    public List<AwemeHashtagResponse> getAllAwemeHashtag(int day, long uid){
        return awemeHashtagRepository.getAllByUidAndAwemeCreateTimeLessThan(uid,LocalDateTime.now().minusDays(day).atZone(ZoneId.systemDefault()).toEpochSecond());
    }

    // @Cacheable(value = "BLOGGER:AWEME:HASHTAG",key = "#uid+'_'+#day+'_'+#size")
    public List<AwemeHashtagResponse> getAwemeHashtag(int day,long uid,int size){
        return awemeHashtagRepository.getTopByUidAndCreateTimeLessThanOrderByAvgView(uid,
                LocalDateTime.now().minusDays(day).atZone(ZoneId.systemDefault()).toEpochSecond(),
                size);
    }

    // @Cacheable(value = "BLOGGER:AWEME:MENTION",key = "#uid+'_'+#day+'_'+#size+'_'+#stats")
    public List<AwemeMentionResponse> getAwemeMention(int day, long uid, int size,int stats){
        if(stats == 2){
            return awemeMentionRepository.getEnterpriseTopByUidAndAwemeCreateTimeLessThanOrderByAvgView(uid,
                    LocalDateTime.now().minusDays(day).atZone(ZoneId.systemDefault()).toEpochSecond(),
                    size);
        }else if(stats == 1){
            return awemeMentionRepository.getTopByUidAndAwemeCreateTimeLessThanOrderByAvgView(uid,
                    LocalDateTime.now().minusDays(day).atZone(ZoneId.systemDefault()).toEpochSecond(),
                    size);
        }
        return null;


    }

    private List<Map<String,Object>> getComments(long awemeId){
        List<Map<String,Object>> comments = new ArrayList<>();
        try{
            val aweme = awemeRepository.findByoAwemeId(awemeId);
            int dateCode = 0;
            if(aweme.isPresent()){
                dateCode = aweme.get().getDatecode();
            }
            String comment = fileTemplate.getAsString(BUCKET_NAME,"video_comment_" + dateCode +"/" + awemeId);
            comments = JsonUtil.jsonParse(comments.getClass(),comment);
        }catch (Exception e){
            return null;
        }

        return comments;

    }

    public Aweme findByAwemeId(long awemeId){
        Optional<Aweme> awemeOptional = awemeRepository.findByoAwemeId(awemeId);
        return awemeOptional.isPresent()?awemeOptional.get():null;
    }


    @Cacheable(value = "BLOGGER:AWEME:WEEK_COUNT",key = "#uid")
    public List<AwemeCountDto> countUseOfDay(int day, long uid){
        return awemeRepository.countDayByUid(uid,LocalDateTime.now().minusDays(day).atZone(ZoneId.systemDefault()).toEpochSecond());
    }

    @Cacheable(value = "BLOGGER:AWEME:HOUR_COUNT",key = "#uid")
    public List<AwemeCountDto> countUseOfHour(int day,long uid){
        return awemeRepository.countHourByUid(uid, DateUtil.beginOfDay(DateUtil.offsetDay(new Date(),-day)).getTime()/1000);
    }


}
